I’m aiming to examine the impact of Chief Sustainability Officer presence (`csopresence1`) on the relationship between pension freezes (`hard_final_Exact_new`) and market-adjusted returns (`market_adjusted_return_w`). I adopt a staggered difference-in-differences (DiD) framework, following a published study design. The treatment sample includes a symmetric event window covering two years before and two years after each firm's defined benefit (DB) pension freeze. Matching is implemented to improve comparability between treated and control firms.
- `hard_final_Exact_new` is a binary variable equal to 1 in the year a firm freezes its DB pension plan for all employees, and 0 otherwise.
- `csopresence1` is a binary indicator equal to 1 if the firm has a Chief Sustainability Officer in a given year, and 0 otherwise. This variable may vary over time depending on the presence or departure of a CSO.
I am running a staggered Difference-in-Differences analysis using the `jwdid` command in Stata to evaluate the impact of a hard freeze on market-adjusted returns, with CSO presence as a moderator. However, when I run:
```stata
estat event, window(-2 2)
```
I only get estimates for event years 0, 1, and 2 — but event times -2 and -1 are missing. This occurs both in the overall sample and within subgroup comparisons using `ores(csopresence1==1)` and `ores(csopresence1==0)`.
I suspect the problem lies in how I generated or restricted the sample around the freeze year. Here's a simplified version of my code pipeline for reproducibility:
---
* STEP 1: Keep only firms that report a freeze status
bysort id: gen has_pension_data = sum(inlist(hard_final_Exact_new, 0, 1))
keep if has_pension_data > 0
* STEP 2: Generate gvar (treatment year)
bysort id (year): gen freeze_year = year if hard_final_Exact_new == 1
bysort id (year): replace freeze_year = freeze_year[_n-1] if missing(freeze_year)
bysort id (year): replace freeze_year = freeze_year[_n+1] if missing(freeze_year)
gen gvar = freeze_year
drop freeze_year
bysort id: egen ever_treated = max(hard_final_Exact_new == 1)
replace gvar = . if ever_treated == 0
* STEP 3: Matching
ssc install kmatch, replace
kmatch ps ever_treated Fund_Status_w ROA_w Firm_Size_w Platn_Size_w Leverage_w, ematch(year ff_12) comsup nn(1) wor idgenerate replace
keep if !missing(_ID_1)
* STEP 4: Create event time and restrict to ±2 years
gen event_time = year - gvar
tab event_time
keep if inrange(event_time, -2, 2)
* STEP 5: Drop observations with missing covariates
```stata
foreach var in market_adjusted_return_w csopresence1 Firm_Size_w ROA_w Leverage_w Market_book_four_w Non_pension_CFO_w STD_CFO_w board_size_w GenderRatiogenderratio_w independent_percentage_w sustainability2_w SUSTAIBILITY_COMITEE_FU Fund_Status_w FUNDING_RATIO_w Platn_Size_w ff_12 year {
drop if missing(`var')
}
* STEP 6: Estimate Staggered DiD (control for industry only, no firm or year FE)
jwdid market_adjusted_return_w, gvar(gvar) tvar(year) hettype(twfe) xattvar(csopresence1) exovar(Firm_Size_w ROA_w Leverage_w Market_book_four_w Non_pension_CFO_w STD_CFO_w board_size_w GenderRatiogenderratio_w independent_percentage_w sustainability2_w SUSTAIBILITY_COMITEE_FU Fund_Status_w FUNDING_RATIO_w Platn_Size_w i.ff_12)
* STEP 7: Estimate Event-time ATTs
estat event, window(-2 2)
estat event, window(-2 2) ores(csopresence1==1)
estat event, window(-2 2) ores(csopresence1==0)
Despite this, I do not get coefficients for `event_time = -2` and `-1`. What am I missing? Could it be an issue with the `gvar` construction, trimming too early, or `jwdid` not recognizing untreated periods?
Any guidance on ensuring the pre-treatment years appear in the event study table would be appreciated.
Thanks in advance!
---
HTML Code:
* STEP 1: Keep only firms that report a freeze status . . . . bysort id: gen has_pension_data = sum(inlist(hard_final_Exact_new, 0, 1)) . . keep if has_pension_data > 0 (3,020 observations deleted) . . . . * STEP 2: Generate gvar (treatment year) . . . . bysort id (year): gen freeze_year = year if hard_final_Exact_new == 1 (5,716 missing values generated) . . bysort id (year): replace freeze_year = freeze_year[_n-1] if missing(freeze_year) (816 real changes made) . . bysort id (year): replace freeze_year = freeze_year[_n+1] if missing(freeze_year) (91 real changes made) . . gen gvar = freeze_year (4,809 missing values generated) . . drop freeze_year . . . . bysort id: egen ever_treated = max(hard_final_Exact_new == 1) . . replace gvar = . if ever_treated == 0 (0 real changes made) . . . . . . * STEP 3: Matching . . . . ssc install kmatch, replace checking kmatch consistency and verifying not already installed... all files already exist and are up to date. . . kmatch ps ever_treated Fund_Status_w ROA_w Firm_Size_w Platn_Size_w Leverage_w, ematch > (year ff_12) comsup nn(1) wor idgenerate replace (51 observations with PS outside common support) Propensity-score nearest-neighbor matching (without replacement) Number of obs = 5,109 Neighbors: min = 1 Treatment : ever_treated = 1 max = 1 Covariates : Fund_Status_w ROA_w Firm_Size_w Platn_Size_w Leverage_w Exact : year ff_12 PS model : logit (pr) Matching statistics ------------------------------------------------------------------------------ | Matched | Controls | Yes No Total | Used Unused Total -----------+---------------------------------+-------------------------------- Treated | 1525 95 1620 | 1525 1964 3489 Untreated | 1525 1964 3489 | 1525 95 1620 Combined | 3050 2059 5109 | 3050 2059 5109 ------------------------------------------------------------------------------ Stored variables Variable Storage Display Value name type format label Variable label ---------------------------------------------------------------------------------------- _ID_1 long %12.0g ID of control 1 . . keep if !missing(_ID_1) (2,759 observations deleted) . . . . . . * STEP 4: Create event time and restrict to ±2 years . . gen event_time = year - gvar (2,175 missing values generated) . . tab event_time event_time | Freq. Percent Cum. ------------+----------------------------------- -1 | 79 9.03 9.03 0 | 83 9.49 18.51 1 | 87 9.94 28.46 2 | 80 9.14 37.60 3 | 74 8.46 46.06 4 | 68 7.77 53.83 5 | 64 7.31 61.14 6 | 59 6.74 67.89 7 | 55 6.29 74.17 8 | 53 6.06 80.23 9 | 42 4.80 85.03 10 | 36 4.11 89.14 11 | 29 3.31 92.46 12 | 26 2.97 95.43 13 | 19 2.17 97.60 14 | 10 1.14 98.74 15 | 4 0.46 99.20 16 | 4 0.46 99.66 17 | 2 0.23 99.89 18 | 1 0.11 100.00 ------------+----------------------------------- Total | 875 100.00 . . keep if inrange(event_time, -2, 2) (2,721 observations deleted) . . . . . . . . . . * STEP 5: Drop observations with missing covariates . . ```stata ` is not a valid command name r(199); . . foreach var in market_adjusted_return_w csopresence1 Firm_Size_w ROA_w Leverage_w Mark > et_book_four_w Non_pension_CFO_w STD_CFO_w board_size_w GenderRatiogenderratio_w indep > endent_percentage_w sustainability2_w SUSTAIBILITY_COMITEE_FU Fund_Status_w FUNDING_RA > TIO_w Platn_Size_w ff_12 year { 2. . drop if missing(`var') 3. . } (58 observations deleted) (0 observations deleted) (0 observations deleted) (0 observations deleted) (0 observations deleted) (0 observations deleted) (2 observations deleted) (1 observation deleted) (0 observations deleted) (4 observations deleted) (0 observations deleted) (19 observations deleted) (0 observations deleted) (0 observations deleted) (0 observations deleted) (0 observations deleted) (0 observations deleted) (0 observations deleted) . . . . . . * STEP 6: Estimate Staggered DiD (control for industry only, no firm or year FE) . . . . jwdid market_adjusted_return_w, gvar(gvar) tvar(year) hettype(twfe) xattvar(csopresenc > e1) exovar(Firm_Size_w ROA_w Leverage_w Market_book_four_w Non_pension_CFO_w STD_CFO_w > board_size_w GenderRatiogenderratio_w independent_percentage_w sustainability2_w SUST > AIBILITY_COMITEE_FU Fund_Status_w FUNDING_RATIO_w Platn_Size_w i.ff_12) WARNING: Singleton observations not dropped; statistical significance is biased (link) (MWFE estimator converged in 11 iterations) HDFE Linear regression Number of obs = 231 Absorbing 2 HDFE groups F( 27, 175) = 1.62 Prob > F = 0.0357 R-squared = 0.2951 Adj R-squared = 0.0735 Within R-sq. = 0.1995 Root MSE = 0.2159 --------------------------------------------------------------------------------------- market_adjusted_ret~w | Coefficient Std. err. t P>|t| [95% conf. interval] ----------------------+---------------------------------------------------------------- __post__#c.__tr__ | Post-Trt | .0218056 .0564926 0.39 0.700 -.089689 .1333001 | __post__#c.__tr__#| c._x_csopresence1 | Post-Trt | .1800449 .0437251 4.12 0.000 .0937485 .2663413 | Firm_Size_w | -.0333592 .0343346 -0.97 0.333 -.1011224 .0344039 ROA_w | .5523711 .4756693 1.16 0.247 -.3864159 1.491158 Leverage_w | -.2668604 .1902003 -1.40 0.162 -.6422422 .1085213 Market_book_four_w | -.001762 .0019322 -0.91 0.363 -.0055754 .0020513 Non_pension_CFO_w | .5187462 .5404702 0.96 0.338 -.5479326 1.585425 STD_CFO_w | 1.842451 1.379336 1.34 0.183 -.8798238 4.564727 board_size_w | .0038435 .0109931 0.35 0.727 -.0178525 .0255396 GenderRatiogenderra~w | .3756645 .2342125 1.60 0.111 -.0865802 .8379092 independent_percent~w | .2041363 .3158852 0.65 0.519 -.4192986 .8275712 sustainability2_w | -.000783 .0012713 -0.62 0.539 -.003292 .001726 SUSTAIBILITY_COMITE~U | .000147 .043223 0.00 0.997 -.0851586 .0854525 Fund_Status_w | .5561143 .8662319 0.64 0.522 -1.153492 2.26572 FUNDING_RATIO_w | .1249579 .1798537 0.69 0.488 -.2300036 .4799194 Platn_Size_w | .019746 .02518 0.78 0.434 -.0299495 .0694416 | ff_12 | 2 | -.0047594 .1222563 -0.04 0.969 -.246046 .2365271 3 | .0431572 .0990414 0.44 0.664 -.1523121 .2386265 4 | -.2774121 .2604377 -1.07 0.288 -.7914151 .236591 5 | .020742 .1198638 0.17 0.863 -.2158226 .2573067 6 | -.0001728 .0915409 -0.00 0.998 -.180839 .1804934 7 | .0761291 .2242298 0.34 0.735 -.3664137 .5186719 8 | .1842103 .1038355 1.77 0.078 -.0207208 .3891414 9 | .0405306 .0936152 0.43 0.666 -.1442295 .2252907 10 | .027867 .0838528 0.33 0.740 -.1376259 .1933598 11 | .0446025 .0995131 0.45 0.655 -.1517978 .2410029 12 | -.0096438 .1109468 -0.09 0.931 -.2286098 .2093222 | _cons | -.5591376 .4552884 -1.23 0.221 -1.4577 .3394252 --------------------------------------------------------------------------------------- Absorbed degrees of freedom: -----------------------------------------------------+ Absorbed FE | Categories - Redundant = Num. Coefs | -------------+---------------------------------------| gvar | 15 0 15 | year | 15 1 14 | -----------------------------------------------------+ . . . . * STEP 7: Estimate Event-time ATTs . . . . estat event, window(-2 2) ------------------------------------------------------------------------------ | Delta-method | Coefficient std. err. z P>|z| [95% conf. interval] -------------+---------------------------------------------------------------- __event__ | 0 | .0278923 .0564498 0.49 0.621 -.0827473 .138532 1 | .0238476 .0564739 0.42 0.673 -.0868393 .1345345 2 | .0138538 .0566067 0.24 0.807 -.0970932 .1248008 ------------------------------------------------------------------------------ . . estat event, window(-2 2) ores(csopresence1==1) ------------------------------------------------------------------------------ | Delta-method | Coefficient std. err. z P>|z| [95% conf. interval] -------------+---------------------------------------------------------------- __event__ | 0 | .121249 .060498 2.00 0.045 .0026751 .2398228 1 | .121249 .060498 2.00 0.045 .0026751 .2398228 2 | .121249 .060498 2.00 0.045 .0026751 .2398228 ------------------------------------------------------------------------------ . . estat event, window(-2 2) ores(csopresence1==0) ------------------------------------------------------------------------------ | Delta-method | Coefficient std. err. z P>|z| [95% conf. interval] -------------+---------------------------------------------------------------- __event__ | 0 | -.0587959 .06056 -0.97 0.332 -.1774914 .0598995 1 | -.0587959 .06056 -0.97 0.332 -.1774914 .0598995 2 | -.0587959 .06056 -0.97 0.332 -.1774914 .0598995 ------------------------------------------------------------------------------
Any guidance on ensuring the pre-treatment years appear in the event study table would be appreciated.
Thanks in advance!
Comment